﻿using System.CodeDom;
using System.ComponentModel;

namespace InterfaceWeaver.CustomTool
{
    /// <summary>
    /// INotifyPropertyChanged helpers
    /// </summary>
    public static class INotifyPropertyChangedHelper
    {
        /// <summary>
        /// Implements the INotifyPropertyChanged interface if not already implemented.
        /// </summary>
        /// <param name="type">The type.</param>
        /// <returns></returns>
        public static CodeTypeDeclaration ImplementINotifyPropertyChanged(this CodeTypeDeclaration type)
        {
            if (!type.IsInheriting<INotifyPropertyChanged>())
            {
                type.BaseTypes.Add(new CodeTypeReference(typeof(INotifyPropertyChanged)));
                type.Members.Add(new CodeMemberEvent
                {
                    Name = "PropertyChanged",
                    Type = new CodeTypeReference(typeof(PropertyChangedEventHandler)),
                    Attributes = MemberAttributes.Public
                });
            }
            return type;
        }


        public static CodeStatement[] CodeRaisePropertyChangedEventSequence(this CodeMemberProperty property)
        {
            return CodeRaisePropertyChangedEventSequence(property.Name);
        }

        /// <summary>
        /// Codes the property changed event condition.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        /// <returns></returns>
        public static CodeStatement[] CodeRaisePropertyChangedEventSequence(string propertyName)
        {
            var propertyChangedReference = new CodeFieldReferenceExpression(new CodeThisReferenceExpression(), "PropertyChanged");
            var propertyChangedVariableReference = new CodeVariableReferenceExpression("propertyChanged");

            var storePropertyChangedStatment = new CodeVariableDeclarationStatement(
                typeof(PropertyChangedEventHandler),
                "propertyChanged",
                propertyChangedReference);

            var raiseEventStatment = new CodeDelegateInvokeExpression(
                propertyChangedVariableReference,
                new CodeThisReferenceExpression(),
                new CodeObjectCreateExpression(
                    typeof(PropertyChangedEventArgs),
                    new CodePrimitiveExpression(propertyName)));

            var eventNotNullCondition = new CodeBinaryOperatorExpression(
                propertyChangedVariableReference,
                CodeBinaryOperatorType.IdentityInequality,
                new CodePrimitiveExpression(null));

            var trueStatment = new CodeStatement[] { new CodeExpressionStatement(raiseEventStatment) };
            var eventNotNullconditionStatment = new CodeConditionStatement(eventNotNullCondition, trueStatment);

            return new CodeStatement[]
                {
                    storePropertyChangedStatment,
                    eventNotNullconditionStatment
                };
        }
    }
}
